﻿using System;
using System.Collections.Generic;
using System.Linq;
using WaitLess.Business.Data.Model.Antwerpen;
using WaitLess.Business.Data.Model.Foursquare.VenuesResponse;
using WaitLess.Business.Model;
using WaitLess.Business.Repositories.Interfaces;
using WaitLess.Business.Services.Interfaces;

namespace WaitLess.Business.Services
{
    public class MunicipalOfficeLoader : IMunicipalOfficeLoader
    {
        private readonly IDistrictshuisRepository _districtshuisRepository;
        private readonly IStadskantoorRepository _stadskantoorRepository;
        private readonly IVenuesRepository _venuesRepository;

        public MunicipalOfficeLoader(IDistrictshuisRepository districtshuisRepository, IStadskantoorRepository stadskantoorRepository,
            IVenuesRepository venuesRepository)
        {
            if (districtshuisRepository == null) throw new ArgumentNullException("districtshuisRepository");
            if (stadskantoorRepository == null) throw new ArgumentNullException("stadskantoorRepository");
            if (venuesRepository == null) throw new ArgumentNullException("venuesRepository");

            _districtshuisRepository = districtshuisRepository;
            _stadskantoorRepository = stadskantoorRepository;
            _venuesRepository = venuesRepository;
        }

        public void GetDistrictshuizen(Action<IEnumerable<MunicipalOffice>> receiveResult)
        {
            if (receiveResult == null) throw new ArgumentNullException("receiveResult");

            _districtshuisRepository.GetAll(result => receiveResult(MapToMunicipalOffices(result)));
        }

        public void GetStadskantoren(Action<IEnumerable<MunicipalOffice>> receiveResult)
        {
            if (receiveResult == null) throw new ArgumentNullException("receiveResult");

            _stadskantoorRepository.GetAll(result => receiveResult(MapToMunicipalOffices(result)));
        }

        public void GetCurrentCheckedInCount(CurrentCheckedInRequest request)
        {
            if (request == null) throw new ArgumentNullException("request");
            if (string.IsNullOrWhiteSpace(request.AccessToken)) throw new ArgumentException("AccessToken", "request");
            if (string.IsNullOrWhiteSpace(request.MunicipalOfficeName)) throw new ArgumentException("MunicipalOfficeName", "request");
            if (request.ReceiveResult == null) throw new ArgumentException("ReceiveResult", "request");
            if (request.ReceiveVenueId == null) throw new ArgumentException("ReceiveVenueId", "request");

            _venuesRepository.GetByName(request.MunicipalOfficeName, venues =>
            {
                GetCurrentVenueCheckIns(request, venues);
            });
        }

        private void GetCurrentVenueCheckIns(CurrentCheckedInRequest request, VenuesResponse venues)
        {
            var venueId = (from venue in venues.response.venues
                           where string.Compare(venue.name, request.MunicipalOfficeName, StringComparison.InvariantCultureIgnoreCase) == 0
                           select venue.id).FirstOrDefault();    //duplicates possible, cannot expect single by name unfortunately

            if (venueId == null)
            {
                request.ReceiveResult(null);
                return;
            }

            _venuesRepository.GetHereNow(venueId, request.AccessToken, hereNow =>
            {
                request.ReceiveResult(hereNow.response.hereNow.count);
                request.ReceiveVenueId(venueId);
            });
        }

        private IEnumerable<MunicipalOffice> MapToMunicipalOffices(Districtshuizen districtshuizen)
        {
            return districtshuizen.districtshuis.Select(d => new MunicipalOffice 
            { 
                Id = d.id, 
                Name = d.naam, 
                Street = d.straat, 
                HouseNumber = d.huisnummer, 
                PostalCode = d.postcode, 
                District = d.district,
                Latitude = d.point_lat,
                Longitude = d.point_lng
            });
        }

        private IEnumerable<MunicipalOffice> MapToMunicipalOffices(Stadskantoren stadskantoren)
        {
            return stadskantoren.stadskantoor.Select(d => new MunicipalOffice
            {
                Id = d.id,
                Name = d.naam,
                Street = d.straat,
                HouseNumber = d.huisnummer,
                PostalCode = d.postcode,
                District = d.district,
                Latitude = d.point_lat,
                Longitude = d.point_lng
            });
        }
    }
}
